EC2 Instance Connect エンドポイントで PrivateWithEgress に配置された EC2 Instance に接続する構成を AWS CDK で作成してみた
こんにちは、製造ビジネステクノロジー部の若槻です。
EC2 Instance Connect エンドポイント(EC2 Instance Connect Endpoint) を使用すると、踏み台ホストなどを使用せずにプライベートサブネット内の EC2 インスタンスに SSH や RDP 接続が可能となります。この機能は昨年 6 月に提供開始されました。
今回は、この EC2 Instance Connect エンドポイントで PrivateWithEgress のサブネットに配置された EC2 Instance に SSH 接続可能とする構成のリソース一式を AWS CDK で作成してみました。
試してみた
CDK コード
リソース一式を作成する CDK コードは次のようになります。
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkSampleStack extends cdk.Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
// VPC の作成
const vpc = new ec2.Vpc(this, 'VPC', {
subnetConfiguration: [
// NAT Gateway を作成するパブリックサブネット
{
cidrMask: 24,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
},
// 接続先の EC2 Instance を作成するプライベートサブネット
// インスタンスから外部への通信を許可するために Egress ルートを追加
{
cidrMask: 24,
name: 'PrivateWithEgress',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
// EC2 Instance Connect Endpoint を作成するプライベートサブネット
{
cidrMask: 24,
name: 'PrivateIsolated',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
],
});
/**
* EC2 Instance Connect Endpoint に関するリソースを作成
*/
// EC2 Instance Connect Endpoint に関連付けるセキュリティグループ
const instanceConnectEndpointSecurityGroup = new ec2.SecurityGroup(
this,
'InstanceConnectEndpointSecurityGroup',
{
vpc,
allowAllOutbound: false,
}
);
// EC2 Instance Connect Endpoint を作成
new ec2.CfnInstanceConnectEndpoint(this, 'InstanceConnectEndpoint', {
subnetId: vpc.selectSubnets({
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
}).subnetIds[0],
securityGroupIds: [instanceConnectEndpointSecurityGroup.securityGroupId],
});
/**
* EC2 Instance と EC2 Instance Connect Endpoint 間の通信を許可するためのルールを設定
*/
// EC2 Instance に関連付けるセキュリティグループ
const ec2InstanceSecurityGroup = new ec2.SecurityGroup(
this,
'Ec2InstanceSecurityGroup',
{
vpc,
allowAllOutbound: false,
}
);
// EC2 Instance Connect Endpoint から EC2 Instance への通信を許可するための Ingress ルール
ec2InstanceSecurityGroup.addIngressRule(
instanceConnectEndpointSecurityGroup,
ec2.Port.tcp(22)
);
// EC2 Instance Connect Endpoint から EC2 Instance への通信を許可するための Egress ルール
instanceConnectEndpointSecurityGroup.addEgressRule(
ec2InstanceSecurityGroup,
ec2.Port.tcp(22)
);
/**
* EC2 Instance および関連リソースを作成
*/
// EC2 Instance を作成
new ec2.Instance(this, 'Ec2Instance', {
vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
instanceType: new ec2.InstanceType('t3.micro'),
machineImage: new ec2.AmazonLinuxImage({
generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2023,
}),
securityGroup: ec2InstanceSecurityGroup,
});
// EC2 Instance から外部への通信は 443 ポートのみ許可
ec2InstanceSecurityGroup.addEgressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(443)
);
}
}
AWS CDK で EC2 Instance Connect エンドポイントを構築する場合は、L1 Construct class である CfnInstanceConnectEndpoint が利用可能なので利用しています。
ちなみに以下の記事にある通り、EC2 Instance Connect エンドポイントの提供開始直後は CfnInstanceConnectEndpoint が未提供だったため、AwsCustomResource を利用しての構築が必要だったようです。
デプロイ、動作確認
前述の CDK の実装をデプロイした様子です。
作成したエンドポイントを使ってマネジメントコンソールから EC2 Instance Connect による接続を実施してみます。ここで選択されているエンドポイント名冒頭の eice
というのは「EC2 Instance Connect Endpoint」の略です。
インスタンスに SSH で接続できました。
インターネット経由で外部ツール(ここでは psql)のダウンロードおよびインストールもできることが確認できました。
[ec2-user@ip-10-0-2-220 ~]$ sudo dnf install postgresql15
Last metadata expiration check: 18:05:21 ago on Sat Sep 28 14:25:01 2024.
Dependencies resolved.
=================================================================================================================================================================
Package Architecture Version Repository Size
=================================================================================================================================================================
Installing:
postgresql15 x86_64 15.8-1.amzn2023.0.1 amazonlinux 1.6 M
Installing dependencies:
postgresql15-private-libs x86_64 15.8-1.amzn2023.0.1 amazonlinux 145 k
Transaction Summary
=================================================================================================================================================================
Install 2 Packages
Total download size: 1.8 M
Installed size: 6.9 M
Is this ok [y/N]: y
Downloading Packages:
(1/2): postgresql15-private-libs-15.8-1.amzn2023.0.1.x86_64.rpm 1.3 MB/s | 145 kB 00:00
(2/2): postgresql15-15.8-1.amzn2023.0.1.x86_64.rpm 11 MB/s | 1.6 MB 00:00
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Total 7.9 MB/s | 1.8 MB 00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : postgresql15-private-libs-15.8-1.amzn2023.0.1.x86_64 1/2
Installing : postgresql15-15.8-1.amzn2023.0.1.x86_64 2/2
Running scriptlet: postgresql15-15.8-1.amzn2023.0.1.x86_64 2/2
Verifying : postgresql15-15.8-1.amzn2023.0.1.x86_64 1/2
Verifying : postgresql15-private-libs-15.8-1.amzn2023.0.1.x86_64 2/2
Installed:
postgresql15-15.8-1.amzn2023.0.1.x86_64 postgresql15-private-libs-15.8-1.amzn2023.0.1.x86_64
Complete!
[ec2-user@ip-10-0-2-220 ~]$ psql --version
psql (PostgreSQL) 15.8
注意点
エンドポイントのサブネットの更新などを行うと、複数作成エラーが発生する場合がある
EC2 Instance Connect エンドポイントが配置されているサブネットの更新などを行うとエンドポイントの再作成が行われますが、その際に CDK デプロイが次のようなエラーになる場合があります。
12:07:25 AM | UPDATE_FAILED | AWS::EC2::InstanceConnectEndpoint | InstanceConnectEndpoint
Resource handler returned message: "You've reached the quota for the maximum number of Instance Connect Endpoints for this subnet. Delete unused Instance Connect Endpoints, or request a quota increase. (Service: Ec
2, Status Code: 400, Request ID: 5d5d8149-4b42-4e62-a92d-ad065afe1211)" (RequestToken: f745bea4-6329-590c-a0b2-6c07319c9731, HandlerErrorCode: ServiceLimitExceeded)
これは各単位ごとのエンドポイントの最大作成数は次のようになっており、今回だと VPC およびサブネットの最大作成数のクォータに抵触したためエラーとなっていました。
単位 | 最大作成数 |
---|---|
AWS アカウントごと | 5 |
VPC あたり | 1 |
サブネットあたり | 1 |
CfnInstanceConnectEndpoint は L1 Construct であり L2 Construct のようにリソース再作成のハンドリングを上手く行ってくれない場合があるため、注意するようにしましょう。
エンドポイントを再作成したら前のエンドポイントがしばらく選択可能になる?
EC2 Instance Connect エンドポイントを CDK で再作成した後に、エンドポイントを使用して EC2 Instance Connect を試そうとすると、再作成前と後のエンドポイントがどちらも選択可能になるようになってしまいました。
これは実際にリソースが残っているわけではなくブラウザのキャッシュの影響によるもののようで、キャッシュを削除したら現在作成されているエンドポイントのみが選択可能になりました。何回か再作成を繰り返していると選択可能なエンドポイントが 3 つ、4 つと増えていったので少し戸惑いました。
おわりに
EC2 Instance Connect エンドポイントで PrivateWithEgress に配置された EC2 Instance に接続する構成のリソース一式を AWS CDK で作成してみました。
まだ L1 Construct のみの提供ですが、設定項目は多くないため、再作成時の複数作成エラーのハンドリングを除くと、CDK での構築も比較的簡単に行えました。
以上